package com.author.surface;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.swing.ComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.Icon;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
import javax.swing.border.BevelBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.border.LineBorder;

import com.author.document.style.DefaultStyleConstant;
import com.author.document.style.StyleChangeNotify;

public final class FontSelectorComboBox extends JComboBox implements
		ActionListener {
	/** Width and height of the Font Selector combo box */
	private static final int	FS_COMBOBOX_WIDTH	= 250;
	private static final int	FS_COMBOBOX_HEIGHT	= 25;
	private static final int	ROW_COUNT			= 16;

	/**
	 * Size and the name of the font using which the items inside the combo box
	 * will be displayed
	 */
	private static final int	FONT_SIZE			= 16;
	private static final String	DEFAULT_FONT_NAME	= DefaultStyleConstant.DEFAULT_STYLE_FONT_NAME;

	/** List of all fonts present in the system */
	private Object[]			fontNames;

	/** Cell renderer for the Font Selector combo box */
	private CellRenderer		cellrenderer;

	/** Scroll Pane for the Font Selector combo box */
	private JScrollPane			scrollPane;

	/** List for the data model of the Font Selector combo box */
	private JList				list;

	/** Current font associated with the document */
	private String				currentFont;

	public FontSelectorComboBox(Object[] fontnames) throws Exception {
		super(fontnames);
		fontNames = fontnames;

		// Set size of the combo box
		setSize(new Dimension(FontSelectorComboBox.FS_COMBOBOX_WIDTH,
				FontSelectorComboBox.FS_COMBOBOX_HEIGHT));
		setPreferredSize(getSize());

		// Set cell renderer
		setMaximumRowCount(FontSelectorComboBox.ROW_COUNT);
		cellrenderer = new CellRenderer();
		setRenderer(cellrenderer);

		// Create scroll pane and set its viewport to view the combo box
		scrollPane = new JScrollPane(this);
		scrollPane.setViewport(new JViewport());
		scrollPane.getViewport().setView(this);

		// Set the combo box to display the default font name which is the
		// "Times
		// New Roman" font
		int indexPos = getDefaultFontIndex(DEFAULT_FONT_NAME);
		String selection = new String();
		if (indexPos > 0) {
			setSelectedIndex(indexPos);
			selection = (String) getItemAt(indexPos);
		} else {
			// if the default font is unavailable then show the name of the font
			// which is occupying position 0
			setSelectedIndex(0);
			selection = (String) getItemAt(0);
		}

		// Set the font that will be used to display the list of font names
		setFont(new Font(selection, Font.PLAIN, FONT_SIZE));
		currentFont = selection;
		setToolTipText(selection);
		setFocusable(false);
		addActionListener(this);
		setVisible(true);
	}

	/**
	 * This method will be executed when the UI updater requests that the Font
	 * Selector Combo Box displays a different font then the font that it is
	 * currently displaying
	 * 
	 * @param Name
	 *            of the font which should be displayed
	 */
	public void setFontName(String fontName) {
		int indexPos = getDefaultFontIndex(fontName);
		if (indexPos != getSelectedIndex()) setSelectedIndex(indexPos);
		setToolTipText(fontName);

		// Update font with new selection and inform notifier of font change
		String previousFont = (String) getSelectedItem();
		StyleChangeNotify styleChangeNotify = StyleChangeNotify
				.getStyleChangeNotify();
		styleChangeNotify.setDocumentFontChange(previousFont, fontName);
	}

	/**
	 * This method will get the index of the default font
	 */
	private int getDefaultFontIndex(String defaultFont) {
		if ((this.fontNames == null) || (this.fontNames.length == 0))
			return -1;
		int len = this.fontNames.length;
		for (int i = 0; i < len; i++) {
			String ss = (String) this.fontNames[i];
			if (ss.equals(defaultFont)) return i;
		}
		return -1;
	}

	/**
	 * When the user selects a font - display the name of that particular font
	 * to the user inside the FS combo box
	 */
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() instanceof JComboBox) {
			JComboBox cb = (JComboBox) e.getSource();

			// Get user selection
			int selectedItemIndex = cb.getSelectedIndex();
			String selection = (String) cb.getItemAt(selectedItemIndex);
			setFont(new Font(selection, Font.PLAIN, FONT_SIZE));

			// Set tool tip text to reflect user selection
			setToolTipText(selection);

			// Update font with new selection and inform notifier of font change
			String previousFont = currentFont;
			currentFont = selection;
			StyleChangeNotify styleChangeNotify = StyleChangeNotify
					.getStyleChangeNotify();
			styleChangeNotify.setDocumentFontChange(previousFont, currentFont);
		}
	}

	protected class CellRenderer extends JLabel implements ListCellRenderer {
		/** Width and height of each cell of the FS combo box */
		private static final int	CELL_WIDTH	= 320;
		private static final int	CELL_HEIGHT	= 30;

		/** Font used to display the items inside the Cell Renderer */
		private Font				font;

		protected CellRenderer() {
			// Set Cell Renderer size
			setSize(new Dimension(CELL_WIDTH, CELL_HEIGHT));
			setPreferredSize(getSize());
			setOpaque(true);

			// Set alignment
			setHorizontalAlignment(LEFT);
			setVerticalAlignment(CENTER);

			// Set Tool Tip text
			setToolTipText("Select a FONT");
		}

		public Component getListCellRendererComponent(JList list, Object value,
				int index, boolean isSelected, boolean hasFocus) {
			// Set text and font to resemble user selection
			String s = (String) value;
			font = new Font(s, Font.PLAIN, FONT_SIZE);
			setFont(font);
			setText((String) s);

			if (isSelected) {
				setBackground(list.getSelectionBackground());
				setForeground(list.getSelectionForeground());
			} else {
				setBackground(list.getBackground());
				setForeground(list.getForeground());
			}
			return this;
		}

	}
}
